import { profile } from '@/utils/decorators';

/**
 * 对 RoomPosition 的扩展，支持跨房间取距离
 */
export class PositionExtension extends RoomPosition {

    /**
     * 跨房间获取距离
     */
    public getDistanceTo(pos: RoomPosition);
    public getDistanceTo(obj: _HasRoomPosition);
    public getDistanceTo(obj: RoomPosition | _HasRoomPosition) {
        const pos = hasRoomPosition(obj) ? obj.pos : obj;
        if (pos.roomName === 'sim') {
            // 如果在模拟房间，直接返回距离
            return this.getRangeTo(pos);
        }
        // 转化为数字统一世界坐标
        const thisCoord = this.toUnifiedCoord();
        const thatCoord = pos.toUnifiedCoord();
        // 计算切比雪夫距离
        return Math.max(Math.abs(thisCoord.x - thatCoord.x), Math.abs(thisCoord.y - thatCoord.y));
    }

    public getTravelDistanceTo(pos: RoomPosition, opts?: PathFinderOpts);
    public getTravelDistanceTo(obj: _HasRoomPosition, opts?: PathFinderOpts);
    public getTravelDistanceTo(obj: RoomPosition | _HasRoomPosition, opts?: PathFinderOpts) {
        // 使用 path finder 计算距离
        const pos = hasRoomPosition(obj) ? obj.pos : obj;
        const options = opts ?? {};
        const path = PathFinder.search(this, pos, {
            ...options,
            maxOps: 2000,
        });
        // 返回路径长度
        if (path.incomplete) {
            return Infinity;
        }
        else {
            return path.path.length;
        }
    }

    @profile
    public toUnifiedCoord() {
        const [_, h, wx, v, wy] = this.roomName.match(/^([WE])([0-9]+)([NS])([0-9]+)$/);
        let { x, y } = this;
        x = h === 'W' ? ~x : x;
        y = v === 'N' ? ~y : y;
        const unifiedX = ~~wx * 50 + x;
        const unifiedY = ~~wy * 50 + y;
        return { x: unifiedX, y: unifiedY };
    }

    public serialize(): SerializedPosString {
        return `${this.x}/${this.y}/${<StrictRoomNameString>this.roomName}`;
    }

    /**
     * @author bencbartlett
     * Stolen from Overmind
     */
    public isPassible() {
        const terrain = Game.map.getRoomTerrain(this.roomName);
        if (terrain.get(this.x, this.y) === TERRAIN_MASK_WALL)
            return false;
        // 视野判断
        const isVisible = Game.rooms[this.roomName] !== undefined;
        if (isVisible) {
            // 有视野就可以多判断一些
            if (this.lookFor(LOOK_CREEPS).length > 0) return false;
            const impassibleStructures = this.lookFor(LOOK_STRUCTURES).filter(s => {
                return s.structureType !== STRUCTURE_ROAD &&
                    s.structureType !== STRUCTURE_CONTAINER &&
                    !(s.structureType == STRUCTURE_RAMPART && ((<StructureRampart>s).my ||
                        (<StructureRampart>s).isPublic));
            });
            return impassibleStructures.length === 0;
        }
        return true;
    }

}

const hasRoomPosition = function (obj: unknown): obj is _HasRoomPosition {
    return obj['pos'] !== undefined;
};

export const deserializePos = (str: string): RoomPosition => {
    const [x, y, roomName] = str.split('/');
    return new RoomPosition(+x, +y, roomName);
};